package mylab.io.store.socket;

import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.experimental.UtilityClass;
import mylab.io.base.model.Msg;
import mylab.io.base.model.impl.SocketEndpoint;
import mylab.io.core.codec.MsgResolver;
import mylab.io.core.context.DefaultCC;
import mylab.io.store.socket.property.TcpClientProperties;
import mylab.io.store.socket.property.TcpServerProperties;
import mylab.io.store.socket.property.UdpMulticastProperties;
import mylab.io.store.socket.property.UdpPeerProperties;
import mylab.io.store.socket.tcp.client.TcpClientCodec;
import mylab.io.store.socket.tcp.client.TcpClientDas;
import mylab.io.store.socket.tcp.server.TcpServerCodec;
import mylab.io.store.socket.tcp.server.TcpServerDas;
import mylab.io.store.socket.udp.multicast.UdpMulticastCodec;
import mylab.io.store.socket.udp.multicast.UdpMulticastDas;
import mylab.io.store.socket.udp.peer.UdpPeerCodec;
import mylab.io.store.socket.udp.peer.UdpPeerDas;

@UtilityClass
public class SocketExpress {

    public <M extends Msg, F> TcpClientDas<M> tcpClient(String serverHost, int serverPort, Class<? extends ByteToMessageDecoder> frameDecoderClass, MsgResolver<M, ByteBuf> msgResolver) {
        TcpClientProperties properties = new TcpClientProperties();
        properties.setServer(new SocketEndpoint(serverHost, serverPort));
        return tcpClient(properties, frameDecoderClass, msgResolver);
    }

    public <M extends Msg, F> TcpClientDas<M> tcpClient(TcpClientProperties properties, Class<? extends ByteToMessageDecoder> frameDecoderClass, MsgResolver<M, ByteBuf> msgResolver) {
        DefaultCC<TcpClientProperties, M> cc = new DefaultCC<>(properties);
        TcpClientCodec<M> codec = new TcpClientCodec<>(cc, msgResolver, frameDecoderClass);
        return new TcpClientDas<>(cc, codec);
    }


    public <M extends Msg, F> TcpServerDas<M> tcpServer(int listenPort, Class<? extends ByteToMessageDecoder> frameDecoderClass, MsgResolver<M, ByteBuf> msgResolver) {
        TcpServerProperties properties = new TcpServerProperties();
        properties.setListen(new SocketEndpoint(null, listenPort));
        return tcpServer(properties, frameDecoderClass, msgResolver);
    }

    public <M extends Msg, F> TcpServerDas<M> tcpServer(TcpServerProperties properties, Class<? extends ByteToMessageDecoder> frameDecoderClass, MsgResolver<M, ByteBuf> msgResolver) {
        DefaultCC<TcpServerProperties, M> cc = new DefaultCC<>(properties);
        TcpServerCodec<M> codec = new TcpServerCodec<>(cc, msgResolver, frameDecoderClass);
        return new TcpServerDas<>(cc, codec);
    }

    public <M extends Msg, F> UdpPeerDas<M> udpPeer(int localPort, boolean isBroadcast, MsgResolver<M, ByteBuf> msgResolver) {
        UdpPeerProperties properties = new UdpPeerProperties();
        properties.setLocal(new SocketEndpoint(null, localPort));
        properties.setBroadcast(isBroadcast);
        return udpPeer(properties, msgResolver);
    }

    public <M extends Msg, F> UdpPeerDas<M> udpPeer(UdpPeerProperties properties, MsgResolver<M, ByteBuf> msgResolver) {
        DefaultCC<UdpPeerProperties, M> cc = new DefaultCC<>(properties);
        UdpPeerCodec<M> codec = new UdpPeerCodec<>(cc, msgResolver);
        return new UdpPeerDas<>(cc, codec);
    }

    public <M extends Msg, F> UdpMulticastDas<M> udpMulticast(String multicastIp, int multicastPort, MsgResolver<M, ByteBuf> msgResolver) {
        UdpMulticastProperties properties = new UdpMulticastProperties();
        properties.setGroup(new SocketEndpoint(multicastIp, multicastPort));
        return udpMulticast(properties, msgResolver);
    }

    public <M extends Msg, F> UdpMulticastDas<M> udpMulticast(UdpMulticastProperties properties, MsgResolver<M, ByteBuf> msgResolver) {
        DefaultCC<UdpMulticastProperties, M> cc = new DefaultCC<>(properties);
        UdpMulticastCodec<M> codec = new UdpMulticastCodec<>(cc, msgResolver);
        return new UdpMulticastDas<>(cc, codec);
    }

}
